package com.t.bricks.bussiness.service.leaveword.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.t.bricks.bussiness.model.leaveword.HearerInfo;
import com.t.bricks.bussiness.model.leaveword.LeaveWordInfo;
import com.t.bricks.bussiness.service.leaveword.LeaveWordService;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.utils.function.data.CacheTxtUtil;
import com.t.bricks.utils.function.data.IntegerUtil;
import com.t.bricks.utils.function.date.TimeUtil;
import com.t.bricks.utils.function.json.JacksonShell;
import com.t.bricks.utils.function.url.URLUtil;

/**
 * 留言板操作类接口定义
 * @author HuangXinBian
 * @DateTime 2021年12月25日 下午7:52:46
 */
@Service
public class LeaveWordServiceImpl implements LeaveWordService {
	
	/**
	 * 超时时间(毫秒)
	 */
	@Value("${server.session.timeout:9000}")
	private String serverSessionTimeout;
	
	/**
	 * 开启通知
	 */
	@Value("${app.notice.enable:0}")
	private int enableNotice;
	
	/**
	 * 超时时间(毫秒)
	 */
	private static long iTimeOut = -1;
	
	/**
	 * 最后清理的时间戳
	 * 提示:时间戳如1581825404040
	 */
	private static long dLastClearTime = 0;
	
	/**
	 * 缓存文件夹路径
	 */
	private static String sCacheFilePath = String.format("%s/temp/cache/LeaveWord",
			System.getProperty("user.dir").replaceAll("\\\\", "/"));
	
	/**
	 * 留言存储集合
	 */
	private static Map<String, LeaveWordInfo> mapLeaveWord = null;
	
	/**
	 * 听众存储集合
	 */
	private static Map<String, HearerInfo> mapHearer = null;
	
	/**
	 * 是否忙碌中,1:忙;0否
	 */
	private static int iBusy = 0;
	
	/**
	 * 取 留言存储集合
	 * @return
	 */
	private Map<String, LeaveWordInfo> getMapLeaveWord() {
		if (null != mapLeaveWord) {
			return mapLeaveWord;
		}
		
		mapLeaveWord = new ConcurrentHashMap<>();//线程安全
		
		return mapLeaveWord;
	}
	
	/**
	 * 取 听众存储集合
	 * @return
	 */
	private Map<String, HearerInfo> getMapHearer() {
		if (null != mapHearer) {
			return mapHearer;
		}
		
		mapHearer = new ConcurrentHashMap<>();//线程安全
		
		return mapHearer;
	}
	
	/**
	 * 初始化,读取最后的记录
	 */
	@PostConstruct//在依赖关系注入完成之后执行,但这里发现问题:比SpringContextUtil被注入早运行
	private void init() {
		iTimeOut = IntegerUtil.strToInt(serverSessionTimeout, 9000) * 60;
		
		List<LeaveWordInfo> list = CacheTxtUtil.readCacheFile(String.format("%sLeaveWordInfo.txt", sCacheFilePath));
		if (null != list && 0 < list.size()) {
			mapLeaveWord = new ConcurrentHashMap<>(list.size());//线程安全
			for (LeaveWordInfo leaveWordInfo : list) {
				mapLeaveWord.put(leaveWordInfo.getsSign(), leaveWordInfo);
			}
		}

		List<HearerInfo> listHearer = CacheTxtUtil.readCacheFile(String.format("%sHearerInfo.txt", sCacheFilePath));
		if (null != listHearer && 0 < listHearer.size()) {
			mapHearer = new ConcurrentHashMap<>(listHearer.size());//线程安全
			for (HearerInfo hearerInfo : listHearer) {
				mapHearer.put(hearerInfo.getsName(), hearerInfo);
			}
		}
		
		if (1 != enableNotice) {
			return;
		}
		
		loopService();//循环操作(多线程)
	}

	/**
	 * 新增留言
	 * @param leaveWordInfo
	 * @param ip
	 * @return
	 */
	@Override
	public MsgEmity addLeaveWord(LeaveWordInfo leaveWordInfo, String ip) {
		if (null == leaveWordInfo) {
			return MsgEmity.err(8001, "留言对象为空!");
		}
		
		if (null == leaveWordInfo.getsSign() || "".equals(leaveWordInfo.getsSign().trim())) {
			return MsgEmity.err(8002, "留言信息唯一编号为空!");
		}
		
		if (leaveWordInfo.getsLeaveWord().contains("\"serverIp\":\"unknown\"")) {
			String tmp = leaveWordInfo.getsLeaveWord().replace("\"serverIp\":\"unknown\"", "\"serverIp\":\"" + ip + "\"");
			leaveWordInfo.setsLeaveWord(tmp);
		}
		
		leaveWordInfo.setsTime(TimeUtil.nowDateTime());
		
		getMapLeaveWord().put(leaveWordInfo.getsSign(), leaveWordInfo);
		
		if (1 != enableNotice) {
			clear();//触发清理
		}
		
		return MsgEmity.success(8999, "请求成功");
	}
	
	/**
	 * 删除留言
	 * @param sSign
	 * @return
	 */
	@Override
	public MsgEmity delLeaveWord(String sSign) {
		if (null == sSign || "".equals(sSign.trim())) {
			return MsgEmity.success(8001, "待删除的键为空!");
		}
		
		if (null == mapLeaveWord || mapLeaveWord.size() < 1) {
			return MsgEmity.success(8002, "没有数据需要删除!");
		}
		
		if (!mapLeaveWord.containsKey(sSign.trim())) {
			return MsgEmity.success(8003, "待删除的键不存在!");
		}
		
		mapLeaveWord.remove(sSign);

		if (1 != enableNotice) {
			clear();//触发清理
		}
		
		return MsgEmity.success(8999, "请求成功");
	}

	/**
	 * 按名称查找留言
	 * @param sName
	 * @return
	 */
	@Override
	public MsgEmity findByName(String sName) {
		if (null == mapLeaveWord) {
			return MsgEmity.err(8001, "没有任何数据");
		}
		
		Map<String, LeaveWordInfo> map = getMapLeaveWord();
		if (!map.containsKey(sName)) {
			return MsgEmity.err(8002, "没有数据");
		}

		if (1 != enableNotice) {
			clear();//触发清理
		}
		
		return new MsgEmity(true, "找到数据", map.get(sName).getsLeaveWord());
	}

	/**
	 * 显示所有留言
	 * @return
	 */
	@Override
	public MsgEmity findAll() {
		if (null == mapLeaveWord) {
			return MsgEmity.err(8001, "没有任何数据");
		}
		
		List<Map<String, Object>> list = new ArrayList<>(mapLeaveWord.size());
		for (Map.Entry<String, LeaveWordInfo> entry : mapLeaveWord.entrySet()) {
			Map<String, Object> map = JacksonShell.toJavaObject(entry.getValue().getsLeaveWord(), Map.class);
			map.put("sTime", entry.getValue().getsTime());
			list.add(map);
		}
		
		return MsgEmity.success(list, "查找数据成功");
	}
	
	/**
	 * 添加听众
	 * @param hearerInfo
	 * @return
	 */
	@Override
	public MsgEmity addHearer(HearerInfo hearerInfo) {
		if (null == hearerInfo) {
			return MsgEmity.err(8001, "听众对象为空!");
		}
		
		if (null == hearerInfo.getsName() || "".equals(hearerInfo.getsName().trim())) {
			return MsgEmity.err(8002, "听众名称为空!");
		}
		
		if (null == hearerInfo.getsNoticeUrl() || "".equals(hearerInfo.getsNoticeUrl().trim())) {
			return MsgEmity.err(8003, "听众接收消息的路径为空!");
		}
		
		getMapHearer().put(hearerInfo.getsName(), hearerInfo);
		
		return MsgEmity.success(8999, "请求成功");
	}
	
	/**
	 * 删除听众
	 * @param sName
	 * @return
	 */
	@Override
	public MsgEmity delHearer(String sName) {
		if (null == sName || "".equals(sName.trim())) {
			return MsgEmity.success(8001, "待删除的键为空!");
		}
		
		if (null == mapHearer || mapHearer.size() < 1) {
			return MsgEmity.success(8002, "没有数据需要删除!");
		}
		
		if (!mapHearer.containsKey(sName.trim())) {
			return MsgEmity.success(8003, "待删除的键不存在!");
		}
		
		mapHearer.remove(sName);
		
		return MsgEmity.success(8999, "请求成功");
	}
	
	/**
	 * 清理过期数据
	 */
	private static void clear() {
		if (null == mapLeaveWord || mapLeaveWord.size() < 1) {
			return;
		}
		
		//--判断是否需要进行清理,注意:这个算法并不严谨,但判断用户超时并不需要很严谨的进行时刻清理--//
		long vNow = System.currentTimeMillis();
		if ((vNow - dLastClearTime) < iTimeOut) {
			return;
		}
		
		Iterator<Map.Entry<String, LeaveWordInfo>> it = mapLeaveWord.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, LeaveWordInfo> entry = it.next();
			LeaveWordInfo leaveWordInfo = entry.getValue();
			
			if (null == leaveWordInfo.getlTermOfValidity()) {
				continue;
			}
			
			if ((vNow - leaveWordInfo.getlTermOfValidity()) > iTimeOut) {
				it.remove();
				Log.debug("留言板'", leaveWordInfo.getsSign(), "'因超时被剔除留言板!");
			}
		}

		if (null == mapHearer || mapHearer.size() < 1) {
			save();
			return;
		}
		
		Iterator<Map.Entry<String, HearerInfo>> itHearer = mapHearer.entrySet().iterator();
		while (itHearer.hasNext()) {
			Map.Entry<String, HearerInfo> entry = itHearer.next();
			HearerInfo hearerInfo = entry.getValue();
			
			if (3 > hearerInfo.getiCallError()) {
				continue;
			}
			
			itHearer.remove();
			Log.debug("听众'", hearerInfo.getsName(), "'因错误次数过多被剔除听众集合!");
		}
		
		save();
	}
	
	/**
	 * 保存当前数据
	 */
	private static void save() {
		if (null != mapLeaveWord && mapLeaveWord.size() > 0) {
			List<LeaveWordInfo> list = new ArrayList<>(mapLeaveWord.size());
			for (Map.Entry<String, LeaveWordInfo> entry : mapLeaveWord.entrySet()) {
				list.add(entry.getValue());
			}
			
			CacheTxtUtil.createCacheFile(list, String.format("%sLeaveWordInfo.txt", sCacheFilePath));
		}

		if (null != mapHearer && mapHearer.size() > 0) {
			List<HearerInfo> list = new ArrayList<>(mapHearer.size());
			for (Map.Entry<String, HearerInfo> entry : mapHearer.entrySet()) {
				list.add(entry.getValue());
			}
			
			CacheTxtUtil.createCacheFile(list, String.format("%sHearerInfo.txt", sCacheFilePath));
		}
	}
	
	/**
	 * 通知
	 */
	private static void notice() {
		if (null == mapHearer || mapHearer.size() < 1) {
			return;
		}
		
		if (null == mapLeaveWord || mapLeaveWord.size() < 1) {
			return;
		}
		
		Map<String, Object> parameters = new HashMap<>(3);
		for (Map.Entry<String, LeaveWordInfo> en : mapLeaveWord.entrySet()) {
			for (Map.Entry<String, HearerInfo> entry : mapHearer.entrySet()) {
				parameters.put("key", entry.getValue().getsNoticeKey());
				parameters.put("msg", en.getValue().getsLeaveWord());
				URLUtil.post(entry.getValue().getsNoticeUrl(), parameters);
			}
		}
	}
	
	/**
	 * 循环操作
	 */
	private static void loopService() {
		new Thread(() -> {
			while(true) {
				try {
					Thread.sleep(2000);
				} catch (Exception e) {
				}
					
				if (1 == iBusy) {
					continue;
				}
				
				try {
					iBusy = 1;
					clear();//触发清理
					notice();//通知
				} finally {
					iBusy = 0;
				}
			}
		}).start();
	}
	
}
